import { _decorator, Component, Node, UITransform, Graphics, Color, instantiate, isValid } from 'cc';
import { createUINode } from '../Utils';
import QuadTree from '../Common/QuadTree';
import { ActorSkillTypeEnum, EnemyTypeEnum, EntityTypeEnum, G, GEnemy, IClientInput, InputTypeEnum, StateTypeEnum } from '../Common';
import { ActorManager } from '../Entity/Actor/ActorManager';
import { EnemyManager } from '../Entity/Enemy/EnemyManager';
import { WeaponManager } from '../Entity/Weapon/WeaponManager';
import { BulletManager } from '../Entity/Bullet/BulletManager';
import { ObjectPoolManager } from '../Runtime/ObjectPoolManager';
import DataManager from '../Runtime/DataManager';
import { EventManager } from '../Runtime/EventManager';
import { EventTypeEnum, UIEnum } from '../Enum';
import { GameLogic } from '../Common/Runtime/GameLogic';
import { ExpManager } from '../Entity/Exp/ExpManager';
import ResourcesManager from '../Runtime/ResourcesManager';
import { RedXManager } from '../Entity/RedX/RedXManager';
import { UIManager } from '../Runtime/UIManager';
import { HPBar } from '../UI/HPBar';
import { SelectManager } from '../Common/Runtime/SelectManager';
import { AttributeManager } from '../Common/Runtime/AttributeManager';
import { Ttbsj } from '../Common/Runtime/SkillManager';
import { EntityShadeColor } from '../Runtime/MainManager';
import { ScrollManager } from '../Entity/Scroll/ScrollManager';
import BagManager from '../Runtime/BagManager';
const { ccclass } = _decorator;

@ccclass('BattleSingleScene')//单机模式
export class BattleSingleScene extends Component {

    bulletStage: Node = null
    expStage: Node = null
    redXStage: Node = null
    labelStage: Node = null
    hpStage: Node = null
    stage: Node = null
    graphics: Graphics = null
    // 选择状态
    selectState: 0 | 1 = 0
    Camera: Node

    async start() {

        this.Camera = this.node.getChildByName('Camera')
        UIManager.Ins.show(UIEnum.BattleUI, null, this.Camera)
        DataManager.Ins.isSingle = true
        DataManager.Ins.initStateData()

        DataManager.Ins.bm = this

        this.generateStage()

        EventManager.Ins.on(EventTypeEnum.clientInput, this.handleClientInput, this)
        GameLogic.Ins.setState(DataManager.Ins.state)
        AttributeManager.Ins.countAttr()
        DataManager.Ins.setActorHp()

        this.generateExpBall()
    }

    update(dt: number) {
        if (DataManager.Ins.state.isPause) {
            if (DataManager.Ins.state.state == StateTypeEnum.win || DataManager.Ins.state.state == StateTypeEnum.lost) {
                if (this.selectState == 0) {
                    this.selectState = 1
                    BagManager.Ins.saveGameOverData()
                    UIManager.Ins.show(UIEnum.GameOverUI, {}, this.Camera)
                }
            } else if (DataManager.Ins.state.actors[0]?.skillPoint > 0) {
                if (this.selectState == 0) {
                    if (DataManager.Ins.state.playerLevel < 6) {
                        SelectManager.Ins.setSelectWeaponPool()
                    } else {
                        SelectManager.Ins.setSelectPool()
                    }
                    /** 没有可选项了 */
                    if (DataManager.Ins.selectPool.length <= 0) {
                        console.log('没有可选项了')
                        DataManager.Ins.state.actors[0].skillPoint--
                        DataManager.Ins.state.isPause = 0
                    } else {
                        this.selectState = 1
                        UIManager.Ins.show(UIEnum.SelectUI, {}, this.Camera)
                    }
                }
            }
            return
        }
        this.selectState = 0
        dt *= DataManager.Ins.state.gameSpeed
        this.render(dt)
        this.actorTick(dt)
        DataManager.Ins.applyInput({

            type: InputTypeEnum.timePass,
            seed: DataManager.Ins.state.seed++,
            totalTime: DataManager.Ins.state.levelState.totalTime += dt,
            dt
        })
    }

    actorTick(dt: number) {
        for (const actor of DataManager.Ins.state.actors) {
            const { id } = actor
            const am = DataManager.Ins.actorMap.get(id)
            am.tick(dt)
        }
    }

    render(dt: number) {
        this.renderActor(dt)
        this.renderEnemy(dt)
        this.renderWeapon(dt)
        this.renderSkill(dt)
        this.renderBullet(dt)
        this.renderExpBall()
        this.renderScroll(dt)
        this.renderRedX()

        this.setEnemySibling()
    }

    renderActor(dt: number) {
        for (const actor of DataManager.Ins.state.actors) {
            const { id, type } = actor
            let am = DataManager.Ins.actorMap.get(id)
            if (!am) {
                const node = createUINode(type)
                am = node.addComponent(ActorManager)
                am.init(actor)
                node.parent = this.stage
                DataManager.Ins.actorMap.set(id, am)
            }
            am.render(actor)

            let hm = DataManager.Ins.HPBarMap.get('e_' + id)
            if (!hm) {

                const size = GameLogic.Ins.getEntitySizeByType(type)
                const prefab = ResourcesManager.Ins.prefabMap.get(EntityTypeEnum.HPBar)
                const hpBar = instantiate(prefab)
                hpBar.parent = this.hpStage
                hm = hpBar.getComponent(HPBar)
                DataManager.Ins.HPBarMap.set('e_' + id, hm)
                hm.setSize(size.w, size.h)
                hm.entity = actor
            }
        }
    }
    renderEnemy(dt: number) {
        for (const enemy of DataManager.Ins.state.enemies) {
            const { id, type } = enemy
            let em = DataManager.Ins.enemyMap.get(id)
            if (!em) {
                const node = ObjectPoolManager.Ins.poolAlloc(type)
                em = node.getComponent(EnemyManager)
                if (!em) {
                    node.parent = this.stage
                    em = node.addComponent(EnemyManager)
                    em.init(enemy)
                }
                em.reset(enemy)
                DataManager.Ins.enemyMap.set(id, em)
            }
            em.render(enemy)
            if (GEnemy[type].enemyType === EnemyTypeEnum.boss) {
                let hm = DataManager.Ins.HPBarMap.get('a_' + id)
                if (!hm) {
                    const size = GameLogic.Ins.getEntitySizeByType(type)
                    const prefab = ResourcesManager.Ins.prefabMap.get(EntityTypeEnum.HPBar)
                    const hpBar = instantiate(prefab)
                    hpBar.parent = this.hpStage
                    hm = hpBar.getComponent(HPBar)
                    DataManager.Ins.HPBarMap.set('a_' + id, hm)
                    hm.setSize(size.w, size.h)
                    hm.entity = enemy
                }
            }
        }
    }
    renderWeapon(dt: number) {
        for (const weapon of DataManager.Ins.state.weapons) {
            const { id, entityType, owner } = weapon
            let wm = DataManager.Ins.weaponMap.get(id)
            if (!wm) {
                const actor = DataManager.Ins.actorMap.get(owner)
                if (actor) {
                    const parent = actor.node
                    if (!isValid(parent, true)) {
                        return
                    }
                    const prefab = ResourcesManager.Ins.prefabMap.get(entityType)
                    if (!prefab) {
                        return
                    }
                    const node = instantiate(prefab)
                    node.parent = parent
                    wm = node.addComponent(WeaponManager)
                    DataManager.Ins.weaponMap.set(id, wm)
                    wm.init(weapon)
                }
            }
            wm.render(weapon, dt)
        }
    }

    renderSkill(dt: number) {
        const skill = DataManager.Ins.state.skill[ActorSkillTypeEnum.tbsj]
        if (skill) {
            this.renderTbsj(skill.data, dt)
        }
    }

    /** 同步射击渲染 */
    renderTbsj(data: Ttbsj, dt: number) {
        const skill7 = data[EntityTypeEnum.weapon7]
        const skill8 = data[EntityTypeEnum.weapon8]

        const fun = (skill: Ttbsj) => {
            const { id, entityType, owner } = skill.weapon
            let wm = DataManager.Ins.tbsjMap.get(id)
            if (skill.state == StateTypeEnum.shoot) {
                if (!wm) {
                    const actor = DataManager.Ins.actorMap.get(owner)
                    if (actor) {
                        const parent = actor.node
                        if (!isValid(parent, true)) {
                            return
                        }
                        const prefab = ResourcesManager.Ins.prefabMap.get(entityType)
                        if (!prefab) {
                            return
                        }
                        const node = instantiate(prefab)
                        node.parent = parent
                        wm = node.addComponent(WeaponManager)
                        DataManager.Ins.tbsjMap.set(id, wm)
                        wm.init(skill.weapon)
                    }
                }
                wm.render(skill.weapon, dt, {
                    color: EntityShadeColor.Flash,
                    direction: skill.direction,
                    state: skill.state
                })
            } else if (skill.state == StateTypeEnum.none) {
                if (wm) {
                    let color = new Color(0, 0, 0, 0)
                    if (skill.time > 0) color = EntityShadeColor.Flash
                    wm.render(skill.weapon, dt, {
                        color,
                        direction: skill.direction,
                        state: skill.state
                    })
                }
            }
        }

        fun(skill7)
        fun(skill8)

    }

    renderBullet(dt: number) {
        for (const bullet of DataManager.Ins.state.bullets) {
            const { id, type } = bullet
            let bm = DataManager.Ins.bulletMap.get(id)
            if (!bm) {
                const node = ObjectPoolManager.Ins.poolAlloc(type)
                bm = node.getComponent(BulletManager)
                if (!bm) {
                    node.parent = this.bulletStage
                    bm = node.addComponent(BulletManager)
                    bm.init(bullet)
                }
                DataManager.Ins.bulletMap.set(id, bm)
                bm.reset(bullet)
            }
            bm.render(bullet, dt)
        }

        for (const bullet of DataManager.Ins.state.enemyBullets) {
            const { id, type } = bullet
            let bm = DataManager.Ins.enemyBulletMap.get(id)
            if (!bm) {
                const node = ObjectPoolManager.Ins.poolAlloc(type)
                bm = node.getComponent(BulletManager)
                if (!bm) {
                    node.parent = this.bulletStage
                    bm = node.addComponent(BulletManager)
                    bm.init(bullet)
                }
                bm.reset(bullet)
                DataManager.Ins.enemyBulletMap.set(id, bm)
            }
            bm.render(bullet, dt)
        }
    }

    renderExpBall() {
        for (const exp of DataManager.Ins.state.exps) {
            const { type, pos, id, state } = exp
            let em = DataManager.Ins.expBallMap.get(id)
            if (!em) {
                const node = ObjectPoolManager.Ins.poolAlloc(EntityTypeEnum.exp)
                node.parent = this.expStage
                em = node.getComponent(ExpManager)
                DataManager.Ins.expBallMap.set(id, em)
                em.init(type, id)
            }
            em.render(pos, state)
        }
    }

    /** 渲染科技卷 */
    renderScroll(dt: Number) {
        for (const scroll of DataManager.Ins.state.scrolls) {
            const { id, pos } = scroll
            let sm = DataManager.Ins.scrollMap.get(id)
            if (!sm) {
                const node = ObjectPoolManager.Ins.poolAlloc(EntityTypeEnum.scroll)
                node.parent = this.expStage
                sm = node.addComponent(ScrollManager)
                DataManager.Ins.scrollMap.set(id, sm)
                sm.init(id, pos)
            }
        }
    }

    renderRedX() {
        for (const redX of DataManager.Ins.state.redXs) {
            const { id, position, state } = redX
            let rm = DataManager.Ins.redXMap.get(id)
            if (!rm) {
                const node = ObjectPoolManager.Ins.poolAlloc(EntityTypeEnum.redX)
                node.parent = this.redXStage
                rm = node.addComponent(RedXManager)
                DataManager.Ins.redXMap.set(id, rm)
                rm.init(id, position)
            }
            rm.render(state)
        }
    }

    graphicsLine() {

        let fun = (quadTree: QuadTree) => {
            this.graphics.rect(
                quadTree.bounds.x,
                quadTree.bounds.y,
                quadTree.bounds.w,
                quadTree.bounds.h,
            )
            quadTree.nodes.forEach(v => {
                fun(v)
            });
        }

        this.graphics.clear()
        fun(DataManager.Ins.quadTree)
        this.graphics.strokeColor = Color.RED
        this.graphics.lineWidth = 5
        this.graphics.stroke()

    }

    setEnemySibling() {

        const siblings = this.stage.children

        if (siblings) {

            siblings.sort((a: Node, b: Node) => {
                return b.position.y - a.position.y
            })

            for (let i = 0; i < siblings.length; i++) {
                siblings[i].setSiblingIndex(i)
            }
        }

    }

    /** 生成舞台 */
    generateStage() {
        const bg = this.node.getChildByName('BG')
        const bgUITransform = bg.getComponent(UITransform)
        bgUITransform.width = G.StageSize.w
        bgUITransform.height = G.StageSize.h

        this.redXStage = createUINode('redXStage')
        this.redXStage.setParent(bg)
        this.redXStage.setSiblingIndex(1)
        this.redXStage.setPosition(0, 0)

        this.expStage = createUINode('expStage')
        this.expStage.setParent(bg)
        this.expStage.setSiblingIndex(2)
        this.expStage.setPosition(0, 0)

        this.stage = createUINode('stage')
        this.stage.setParent(bg)
        this.stage.setSiblingIndex(3)
        this.stage.setPosition(0, 0)

        const uiTransform = this.stage.getComponent(UITransform)
        uiTransform.setAnchorPoint(0.5, 0.5)
        uiTransform.width = G.StageSize.w
        uiTransform.height = G.StageSize.h
        this.graphics = this.stage.addComponent(Graphics)

        this.hpStage = createUINode('HPBar')
        this.hpStage.setParent(bg)
        this.hpStage.setSiblingIndex(4)
        this.hpStage.setPosition(0, 0)

        this.bulletStage = createUINode('bulletStage')
        this.bulletStage.setParent(bg)
        this.bulletStage.setSiblingIndex(5)
        this.bulletStage.setPosition(0, 0)

        this.labelStage = createUINode('labelStage')
        this.labelStage.setParent(bg)
        this.labelStage.setSiblingIndex(6)
        this.labelStage.setPosition(0, 0)
    }

    /** 开局默认给几个经验球 */
    generateExpBall() {

        const count = AttributeManager.Ins.startExp
        for (let i = 0; i < count; i++) {

            const v2 = {
                x: (Math.random() * 100 + 100),
                y: (Math.random() * 100 + 100)
            }
            if ((Math.random() - 0.5) < 0) v2.x *= -1
            if ((Math.random() - 0.5) < 0) v2.y *= -1

            GameLogic.Ins.addExpBall(v2, DataManager.Ins.state)
        }

    }

    handleClientInput(input: IClientInput) {
        if (DataManager.Ins.state.isPause) {
            return
        }
        DataManager.Ins.applyInput(input)
    }

    onDestroy() {
        EventManager.Ins.off(EventTypeEnum.clientInput, this.handleClientInput, this)

    }
}